package at.dcmspl;

import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.ejb.EJBException;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

/**
 * The Service to access the Dicom Queue
 * @author Hannes Stornig, Gosch Daniel
 */
@Stateless
public class DcmQueueService implements DcmQueueServiceRemote {
    
    @PersistenceContext
    private EntityManager em;
    @EJB DcmFileExport dcmFileExport;

    /**
    * Creates a DcmQueue
    * @param name Name of the Queue (Type String)
    */
    @Override
    public void createDcmQueue(String name) {
        DcmQueueSimple queue = new DcmQueueSimple(name);
        em.persist(queue);
        Logger.getLogger(DcmQueueService.class.getName()).log(Level.INFO, "### Queue erstellt: {0}", name);
    }
    
    /**
    * Creates a DcmQueue
    * @param dcmqueue (Type DcmQueueSimple)
    */
    @Override
    public void createDcmQueue(DcmQueueSimple dcmqueue) {
        em.persist(dcmqueue);
        Logger.getLogger(DcmQueueService.class.getName()).log(Level.INFO, "### Queue erstellt: {0}", dcmqueue.getName());
    }
    
    /**
    * Updates the delivered DicomQueue
    * @param dcmqueue (Type DcmQueueSimple)
    */
    @Override
    public void updateDcmQueue(DcmQueueSimple dcmqueue) {
        em.merge(dcmqueue);
        Logger.getLogger(DcmQueueService.class.getName()).log(Level.INFO, "### Queue geupdated: {0}", dcmqueue.getName());
    }

    /**
    * Removes the delivered DicomQueue
    * @param dcmqueue (Type DcmQueueSimple)
    */
    @Override
    public void removeDcmQueue(DcmQueueSimple dcmqueue) {
        em.remove(em.merge(dcmqueue));
    }    

    /**
    * Findes a DicomQueue
    * @param id (Type Object)
    */
    @Override
    public DcmQueueSimple findDcmQueue(Object id) {
        return em.find(DcmQueueSimple.class, id);
    }
    
    /**
    * Findes a DcmQueue by the delivered name
    * @param name (Type String)
    * @return DcmQueueSimple
    */
    @Override
    public DcmQueueSimple findDcmQueueByName(String name) {
        try {
            return  em.createNamedQuery(DcmQueueSimple.FIND_BY_NAME, DcmQueueSimple.class)
                    .setParameter("name", name)
                    .setMaxResults(1)
                    .getSingleResult();
        } catch (NoResultException ex) {
            Logger.getLogger(DcmQueueService.class.getName()).log(Level.SEVERE, "No Result found for the Queue {0}",name);
            return null;
        }
    }
        
    /**
    * delivers the First DcmQueue
    * @return DcmQueueSimple
    */    
    @Override
    public DcmQueueSimple getFirst() {
        try {
            return em.createNamedQuery(DcmQueueSimple.FIND_ALL, DcmQueueSimple.class)
                    .setMaxResults(1)
                    .getSingleResult();
        } catch (NoResultException ex) {
            Logger.getLogger(DcmQueueService.class.getName()).log(Level.SEVERE, "No Result found. Exception: {0}",ex);
            return null;
        }
    }    
    
    /**
    * Adds a Dicom File with the delivered Queue Name and the Dicom File Name
    * @param dcmQueueName Is the name of the specific DcmQueue
    * @param dcmFileName Is the name of the dcmFile to add
    */    
    @Override
    public void addDcmFile(String dcmQueueName, String dcmFileName) {   
        //TODO Pfad definieren
        String dateiname;
        DcmQueueSimple queue = this.findDcmQueueByName(dcmQueueName);
        if(queue!=null){
             try {
                //Exportiere DCM File...
                dateiname = dcmFileExport.exportDcmFile(dcmFileName);
                Logger.getLogger(DcmQueueService.class.getName()).log(Level.INFO, "### Exportiere DicomFile {0}",dateiname);
            }
            catch(IOException iox) {
                throw new EJBException("Export fuer DcmFile "+ dcmFileName +" fehlgeschlagen: "+iox);
            }
            
            queue = em.merge(queue);
            DcmFile dcmFile = new DcmFile(dcmFileName,dateiname,queue);
            queue.addDcmFile(dcmFile);
            //Dateiexport

        }else{
            Logger.getLogger(DcmQueueService.class.getName()).log(Level.INFO, "### ERROR, Queue {0} nicht gefunden!", dcmQueueName);
        }
    }
    
    /**
    * Adds a Dicom File with the delivered Queue and the Dicom File Name
    * @param dcmqueue Is the specific DicomQueue in which the DicomFile is added to
    * @param dcmFileName Is the name of the dcmFile to add
    */    
    @Override
    public DcmQueueSimple addDcmFile(DcmQueueSimple dcmqueue, String dcmFileName) {
        String dateiname;
        try {
            //Exportiere DCM File...
            dateiname = dcmFileExport.exportDcmFile(dcmFileName);
            Logger.getLogger(DcmQueueService.class.getName()).log(Level.INFO, "### Exportiere DicomFile {0}",dateiname);
        }
        catch(IOException iox) {
            throw new EJBException("Export fuer DcmFile "+ dcmFileName +" fehlgeschlagen Exception: "+iox);
        }
        dcmqueue = em.merge(dcmqueue);
        DcmFile item = new DcmFile(dcmFileName,dateiname,dcmqueue);
        dcmqueue.addDcmFile(item);

        return dcmqueue;
    }
    
    /**
    * Removes a Dicom File in the delivered Queue
    * @param dcmqueue Is the specific DicomQueue in which the DicomFile is added to
    * @param dcmFile Is the specific DicomFile
    * @return DcmQueueSimple
    */    
    @Override
    public DcmQueueSimple removeDcmFile(DcmQueueSimple dcmqueue, DcmFile dcmFile) {
        dcmqueue = em.merge(dcmqueue);
        dcmqueue.removeDcmFile(dcmFile);
        
        //Datei Löschen
        try {
            dcmFileExport.removeDcmFile(dcmFile.getDateiname()+dcmFileExport.getENDGUELTIGE_EXTENSION());
        } catch (IOException ex) {
            Logger.getLogger(DcmQueueService.class.getName()).log(Level.SEVERE, null, ex);
        }
        return dcmqueue;
    }
    
    /**
    * Retrieves and removes the head of this queue, or returns null if this queue is empty
    * @param dcmqueue Is the specific DicomQueue
    * @return DcmFile
    */   
    @Override
    //TODO Alle Funktionen auf Queue Leer Exceptions umstellen
    public DcmFile poolDcmFile(DcmQueueSimple dcmqueue){
        dcmqueue = em.merge(dcmqueue);
        try{
            DcmFile dcmFile = dcmqueue.pool();

            //Löschen des Dicom Files im FS
            try {
                dcmFileExport.removeDcmFile(dcmFile.getDateiname()+dcmFileExport.getENDGUELTIGE_EXTENSION());
                Logger.getLogger(DcmQueueService.class.getName()).log(Level.INFO, "dcmFile aus dem Filesystem gelöscht");
            } catch (IOException ex) {
                Logger.getLogger(DcmQueueService.class.getName()).log(Level.SEVERE, null, ex);
            }
            return dcmFile;
        }catch(NullPointerException ex){
            Logger.getLogger(DcmQueueService.class.getName()).log(Level.SEVERE, "Queue ist Leer");
        }
        return null;
    }
    
    /**
    * Retrieves the DicomObjekt Element at the specific Position of the Queue
    * @param dcmqueue The specific DicomQueue
    * @return DcmFile
    */   
    @Override
    public DcmFile peekDcmFile(DcmQueueSimple dcmqueue){
        dcmqueue = em.merge(dcmqueue);
        DcmFile dcmFile = dcmqueue.peek();
        return dcmFile;
           
    }
    
    /**
    * Retreaves the Element on the specified Position of the Queue and Removes it
    * TransactionAttributeType.Required
    * @param dcmqueue The specific DicomQueue
    * @param index The Index of the specific DicomFile
    */
    @Override
    public DcmFile movetoHead(DcmQueueSimple dcmqueue, int index){
        dcmqueue = em.merge(dcmqueue);
        try{
            DcmFile dcmFile = dcmqueue.movetoHead(index);
               
            //Löschen des Dicom Files im FS
            try {
                dcmFileExport.removeDcmFile(dcmFile.getDateiname()+dcmFileExport.getENDGUELTIGE_EXTENSION());
                Logger.getLogger(DcmQueueService.class.getName()).log(Level.INFO, "dcmFile aus dem Filesystem gelöscht");
            } catch (IOException ex) {
                Logger.getLogger(DcmQueueService.class.getName()).log(Level.SEVERE, null, ex);
            }
            return dcmFile;
        }catch(NullPointerException ex){
            Logger.getLogger(DcmQueueService.class.getName()).log(Level.SEVERE, "Queue ist Leer");
        }
        return null;
    }
    
    /**
    * Moves the Element on the specified Position to the Head of the Queue
    * TransactionAttributeType.Required
    * @param dcmqueue The specific DicomQueue
    * @param index The Index of the specific DicomFile
    */
    @Override
    public void remove(DcmQueueSimple dcmqueue){
        dcmqueue = em.merge(dcmqueue);
        try{
            DcmFile dcmFile = dcmqueue.remove();
            //Löschen des Dicom Files im FS
            try {
                dcmFileExport.removeDcmFile(dcmFile.getDateiname()+dcmFileExport.getENDGUELTIGE_EXTENSION());
                Logger.getLogger(DcmQueueService.class.getName()).log(Level.INFO, "dcmFile {0} aus dem Filesystem gelöscht",dcmFile.getDateiname());
            } catch (IOException ex) {
                Logger.getLogger(DcmQueueService.class.getName()).log(Level.SEVERE, null, ex);
            }
        }catch (NullPointerException ex){
            Logger.getLogger(DcmQueueService.class.getName()).log(Level.SEVERE, "###Error {0}",ex);
        }

    }
    
    /**
    * Retrieves the DicomObjekt Element at the specific Position of the Queue
    * @return DcmFile
    * @param dcmqueue The specific DicomQueue
    * @param index The Index of the specific DicomFile
    */
    @Override
    public DcmFile elementAt(DcmQueueSimple dcmqueue,int index){
        dcmqueue = em.merge(dcmqueue);
        return dcmqueue.elementAt(index);
    }
    
    /**
    * Retrieves the Count of DicomQueues
    * @return long
    */
    @Override
    public long count() {
        return ((Long) em.createQuery("select count(q) from DcmQueueSimple q").getSingleResult()).longValue();
    }

    /**
    * Retrieves all DicomQueues
    * @return List<DcmQueueSimple>
    */
    @Override
    public List<DcmQueueSimple> findAll() {
        return em.createNamedQuery(DcmQueueSimple.FIND_ALL, DcmQueueSimple.class).getResultList();
    }

}
